package cn.tedu.lbs.basic.web.service;

import cn.tedu.lbs.basic.web.repository.AdminRepository;
import cn.tedu.lbs.basic.web.repository.BusinessCategoryRepository;
import cn.tedu.lbs.basic.web.repository.BusinessRepository;
import cn.tedu.lbs.basic.web.repository.StoreRepository;
import cn.tedu.lbs.basic.web.util.AuthenticationContextUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tarena.lbs.attach.api.AttachApi;
import com.tarena.lbs.base.common.utils.Asserts;
import com.tarena.lbs.base.protocol.exception.BusinessException;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.common.passport.enums.Roles;
import com.tarena.lbs.common.passport.principle.UserPrinciple;
import com.tarena.lbs.pojo.attach.param.PicUpdateParam;
import com.tarena.lbs.pojo.basic.param.BusinessParam;
import com.tarena.lbs.pojo.basic.po.AdminPO;
import com.tarena.lbs.pojo.basic.po.BusinessPO;
import com.tarena.lbs.pojo.basic.po.StorePO;
import com.tarena.lbs.pojo.basic.query.BusinessQuery;
import com.tarena.lbs.pojo.basic.vo.BusiStoreVO;
import com.tarena.lbs.pojo.basic.vo.BusinessCategoryVO;
import com.tarena.lbs.pojo.basic.vo.BusinessVO;
import com.tarena.lbs.pojo.basic.vo.StoreVO;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class BusinessService {
    @Autowired
    private BusinessRepository businessRepository;
    @Autowired
    private BusinessCategoryRepository businessCategoryRepository;
    @Autowired
    private AdminRepository adminRepository;
    @Autowired
    private StoreRepository storeRepository;
    public PageResult<BusinessVO> pageList(BusinessQuery businessQurey) throws BusinessException {
        PageResult<BusinessVO> voPage=new PageResult<>(businessQurey);
        //分页查询逻辑 就是按照PageResult属性要求 挨个封装 属性值
        //但是经过 分析 pageNo pageSize就是入参值 total objects(业务数据列表) 从数据库查
        //totalPage 总页数(业务边界 谁来计算 后端计算) 100 10=10页 101 10 =11页
        //使用分页查询的插件 pageHelper
        PageInfo pageInfo = getPageResult(businessQurey);
        //1.查询total select count(*) from lbs_business where 搜索入参拼接
        //2.查询list select * from lbs_business where 搜索入参拼接 limit from,size
        voPage.setTotal(pageInfo.getTotal());
        //分页查询结果 核心list 需要转化po成vo
        List<BusinessPO> pos = pageInfo.getList();
        List<BusinessVO> vos=null;
        if (pos!=null&&pos.size()>0){
            //第一种方案 循环pos 初始化vos 每循环一个po 转化一个vo 放到vos里
            //第二种方案 stream流
            vos=pos.stream().map(po->{
                //pos每个元素 都会赋值给po变量
                //关心的映射算法 怎么把这个po转化成vo
                BusinessVO vo=new BusinessVO();
                BeanUtils.copyProperties(po,vo);
                return vo;
            }).collect(Collectors.toList());
        }
        voPage.setObjects(vos);
        return voPage;
    }

    private PageInfo getPageResult(BusinessQuery businessQurey) throws BusinessException {
        //组织 查询的业务条件 根据不同的角色 封装 id=#{busienssId};
        Integer businessId = checkAndGetBusinessId();
        QueryWrapper<BusinessPO> queryWrapper;
        if (businessId!=null){
            queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("id",businessId);
        }else{
            queryWrapper=Wrappers.emptyWrapper();
        }
        PageHelper.startPage(businessQurey.getPageNo(),businessQurey.getPageSize());
        //直接利用query条件中非空的属性 拼接where语句 直接执行sql查询
        List<BusinessPO> pos = businessRepository.list(queryWrapper);
        log.info("分页插件开启,pos类型为:{}",pos.getClass().getName());
        //封装pageInfo对象
        PageInfo pageInfo=new PageInfo<>(pos);
        return pageInfo;
    }
    private Integer checkAndGetBusinessId() throws BusinessException {
        //1.拿到认证对象
        UserPrinciple userPrinciple = AuthenticationContextUtil.get();
        //2.断言空
        Asserts.isTrue(userPrinciple==null,new BusinessException("-2","用户认证解析失败"));
        //3.拿到角色
        Roles role = userPrinciple.getRole();
        Integer businessId=null;
        //4.如果角色是SHOP 需要给businessId赋值
        if (role==Roles.SHOP){
            AdminPO po = adminRepository.getById(userPrinciple.getId());
            Asserts.isTrue
                    (po==null,new BusinessException("-2","登录用户根本不存在"));
            businessId=po.getBusinessId();
        }
        return businessId;
    }
    public List<BusinessCategoryVO> categoryList() {
        return businessCategoryRepository.list().stream().map(po->{
            BusinessCategoryVO vo=new BusinessCategoryVO();
            BeanUtils.copyProperties(po,vo);
            return vo;
        }).collect(Collectors.toList());
    }
    @Transactional(rollbackFor = Exception.class)
    public void save(BusinessParam param)throws BusinessException {
        //1.获取解析的认证对象 判断用户权限
        checkRole(Roles.ADMIN);
        //2.封装数据新增 保证新增幂等
        Integer id=saveOnce(param);
        //3.绑定图片
        bindPictures(param,id);
    }

    private Integer saveOnce(BusinessParam param) throws BusinessException {
        //幂等设计 不能出现同一个商家名称 多次
        //利用 入参的商家名称 查询已有的商家数据数量
        checkBusinessCount(param.getBusinessName());
        //param表单入参类型 并不一定和po 和表格一一对象不能直接写入数据库 转化po并且补齐数据
        BusinessPO poParam=new BusinessPO();
        BeanUtils.copyProperties(param,poParam);
        //entryTime
        poParam.setEntryTime(new Date());
        //审核意见非空 同意
        poParam.setAuditRemarks("同意");
        //商家状态非空 1
        poParam.setBusinessStatus(1);
        //调用仓储层新增 mybatis 具备一个能力 给po对象的主键属性 回填数据
        businessRepository.save(poParam);
        return poParam.getId();
    }

    private void checkBusinessCount(String businessName) throws BusinessException {
        //select count(0) from lbs_business where business_name=?
        QueryWrapper queryWrapper=new QueryWrapper();
        queryWrapper.eq("business_name",businessName);
        long count = businessRepository.count(queryWrapper);
        Asserts.isTrue(count>0,new BusinessException("-2","商家名称重复"));
    }

    private void checkRole(Roles role) throws BusinessException {
        //线程下游 拿到认证对象
        UserPrinciple userPrinciple = AuthenticationContextUtil.get();
        //如果认证解析有问题 拿到的是null
        Asserts.isTrue(userPrinciple==null,
                new BusinessException("-2","用户认证解析失败"));
        //如果和要求的角色不同 说明没有符合业务权限
        Asserts.isTrue(userPrinciple.getRole()!=role,
                new BusinessException("-2","用户权限不足"));

    }
    @DubboReference(retries = 5)
    private AttachApi attachApi;
    private void bindPictures(BusinessParam param,Integer businessId) throws BusinessException {
        //1.封装入参 2张图片 licenseUrl logoUrl 同一个商家businessId 100 200
        List<PicUpdateParam> params=new ArrayList<>();
        //1.1封装一个绑定营业执照
        PicUpdateParam license=new PicUpdateParam();
        license.setBusinessId(businessId);
        license.setBusinessType(100);
        //licenseUrl=http://localhost:9081/static/2932e9fn23fh923fj023fj.png
        license.setFileUuid(parseFileUuid(param.getBusinessLicense()));
        params.add(license);
        //1.2封装一个绑定商家logo
        PicUpdateParam logo=new PicUpdateParam();
        logo.setBusinessId(businessId);
        logo.setBusinessType(200);
        //licenseUrl=http://localhost:9081/static/2932e9fn23fh923fj023fj.png
        logo.setFileUuid(parseFileUuid(param.getBusinessLogo()));
        params.add(logo);
        //2.调用接口
        try{
            boolean result = attachApi.batchUpdateBusiness(params);
            if (!result){
                throw new BusinessException("-2","图片绑定业务失败");
            }
        }catch (RpcException e){
            //将新增商家回滚
            throw new BusinessException("-2","图片绑定调用失败");
        } catch (BusinessException e) {
            throw new RuntimeException(e);
        }

    }

    private String parseFileUuid(String businessLicense) {
        return businessLicense.split("/")[4];
    }

    public BusiStoreVO busiStores(Integer id) throws BusinessException {
        //查询商家
        BusinessPO po = businessRepository.getById(id);
        Asserts.isTrue(po==null,new BusinessException("-2","商家不存在"));
        //转化vo
        BusiStoreVO vo=new BusiStoreVO();
        BeanUtils.copyProperties(po,vo);//唯独缺少storeVOList
        //利用id 查询所有店铺
        //select * from lbs_store where business_id=?
        QueryWrapper<StorePO> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("business_id",id);
        List<StorePO> pos = storeRepository.list(queryWrapper);
        if (pos!=null&&pos.size()>0){
            vo.setStoreVOList(pos.stream().map(sPo->{
                StoreVO sVo=new StoreVO();
                BeanUtils.copyProperties(sPo,sVo);
                return sVo;
            }).collect(Collectors.toList()));
        }
        return vo;
    }
}
















